/*
 * Copyright (c) Family. All Rights Reserved
 */

package com.driving.exam.spider;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Component;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.driving.exam.entity.School;
import com.driving.exam.service.ISchoolService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import cn.guet.base.spider.http.HttpClientUtil;
import lombok.RequiredArgsConstructor;

/**
 * 驾校任务
 *
 * @author SAGITTAR
 */
@RequiredArgsConstructor
@Component(value = "schoolSpider")
public class SchoolSpider {

    private static final Logger LOGGER = LogManager.getLogger(SchoolSpider.class);

    private static final String SCHOOL_ROOT_PAGE = "http://www.jiakaobaodian.com";

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    private final ISchoolService schoolService;

    public void execute() throws Exception {
        QueryWrapper<School> existWrapper = new QueryWrapper<>();
        List<String> bigAreaList = schoolService.list(existWrapper).stream().map(School::getBigArea)
            .collect(Collectors.toList());
        String webPage = HttpClientUtil.getWebPage(SCHOOL_ROOT_PAGE + "/school/");
        List<String> provinceUrlList = Jsoup.parse(webPage).select(".list-w").select("a").stream()
            .map(a -> a.attr("href")).collect(Collectors.toList());
        for (String province : provinceUrlList) {
            String provincePage = HttpClientUtil.getWebPage(SCHOOL_ROOT_PAGE + province);
            Document provinceDocument = Jsoup.parse(provincePage);
            // 省份名称或直辖市名称
            String provinceTitle = provinceDocument.select(".common-channel-crumb").select("a").last().ownText();
            String provinceName = provinceTitle.substring(0, provinceTitle.indexOf("驾校"));
            if (bigAreaList.contains(provinceName)) {
                continue;
            }
            Elements cityOrDistrictList;
            // 判断是否直辖市
            if (isDirectCity(province)) {
                // 构造直辖市节点
                cityOrDistrictList = new Elements(new Element("a").attr("href", province).text(provinceName));
            } else {
                cityOrDistrictList = provinceDocument.select(".list-w").select("a");
            }
            // 遍历城市或行政区
            for (Element cityOrDistrict : cityOrDistrictList) {
                String pageUrl = SCHOOL_ROOT_PAGE + cityOrDistrict.attr("href") + "%sf.html";
                // 遍历页码，第一页开始
                for (int page = 1;; page++) {
                    Document currentPage;
                    try {
                        currentPage = Jsoup.parse(HttpClientUtil.getWebPage(String.format(pageUrl, page)));
                    } catch (IOException exception) {
                        if (exception.getLocalizedMessage().contains("404")) {
                            break;
                        }
                        continue;
                    }
                    List<School> schoolPageList = new ArrayList<>(10);
                    for (Element schoolEle : currentPage.select("a.img-w")) {
                        School theSchool = new School();
                        theSchool.setBigArea(provinceName);
                        theSchool.setSmallArea(cityOrDistrict.ownText());
                        String schoolUrl = SCHOOL_ROOT_PAGE + schoolEle.attr("href");
                        theSchool.setSchoolUrl(schoolUrl);
                        try {
                            Document schoolDoc = Jsoup.parse(HttpClientUtil.getWebPage(schoolUrl));
                            theSchool.setName(schoolDoc.select("a.title").first().ownText());
                            String price = schoolDoc.select("p.price").first().ownText();
                            String priceTag = "￥";
                            if (StringUtils.contains(price, priceTag)) {
                                price = StringUtils.substringAfter(price, priceTag);
                            }
                            theSchool.setPrice(StringUtils.trim(price));
                            String telephone = schoolDoc.select("p.phone").first().ownText().substring(5);
                            theSchool.setTelephone(StringUtils.trim(telephone));
                            String address = schoolDoc.select("p.field").first().ownText().substring(5);
                            theSchool.setAddress(StringUtils.trim(address));
                            Element detail = schoolDoc.select(".frame-l-r").select(".content").first();
                            theSchool.setDetail(StringUtils.trim(detail.html()));
                            Element coverEle = schoolDoc.select("div.images-list").select("img").first();
                            if (Objects.nonNull(coverEle)) {
                                theSchool.setCoverUrl(coverEle.attr("src"));
                            }
                        } catch (Exception e) {
                            LOGGER.error(e.getLocalizedMessage(), e);
                        }
                        schoolPageList.add(theSchool);
                    }
                    if (!schoolPageList.isEmpty()) {
                        try {
                            schoolService.saveBatch(schoolPageList);
                        } catch (Exception e) {
                            LOGGER.error(e.getLocalizedMessage(), e);
                        }
                    }
                    String logInfo = provinceName + "-" + cityOrDistrict.ownText() + "-" + page + "-";
                    schoolPageList.forEach(school -> {
                        try {
                            LOGGER.info(logInfo + OBJECT_MAPPER.writeValueAsString(school));
                        } catch (JsonProcessingException e) {
                            LOGGER.error(e.getLocalizedMessage());
                        }
                    });
                    TimeUnit.SECONDS.sleep(1);
                }
                TimeUnit.SECONDS.sleep(1);
            }
            TimeUnit.SECONDS.sleep(1);
        }
    }

    private boolean isDirectCity(String url) {
        for (String city : Arrays.asList("beijing", "shanghai", "tianjin", "chongqing")) {
            if (url.contains(city)) {
                return true;
            }
        }
        return false;
    }
}
